Skip to content

Fix incomplete type checking for arrays with struct element types - #2

Draft
wuzhi456 with Copilot wants to merge 4 commits into
my-project3from
copilot/implement-type-system-and-symbol-table-again
Draft

Fix incomplete type checking for arrays with struct element types#2
wuzhi456 with Copilot wants to merge 4 commits into
my-project3from
copilot/implement-type-system-and-symbol-table-again

Conversation

Copilot AI commented Nov 13, 2025

Copy link
Copy Markdown

Fix incomplete type checking for arrays with struct element types

Plan

  • Understand the issue: Array element types must be complete when the array is specified
  • Fix incomplete type checking to properly check array element types at the point of array specification
  • Test the fix with err_04.splc
  • Verify no regressions with other test cases
  • Fix duplicate parameter detection in function declarations

Implementation

Array Type Checking (Initial Fix)

Added requiresImmediateCompletenessCheck() method to distinguish between:

  • Array types: Must check element completeness immediately (per spec)
  • Direct struct types: Can defer check for global variables (per v4 spec)

Modified global variable definition to:

  1. Check arrays of incomplete structs immediately and error
  2. Defer checking for direct struct types (global variables only)

Function Declaration Parameter Checking (New Fix)

Added duplicate parameter name detection for function declarations:

  • Track parameter names in a HashSet while processing
  • Report redefinition error if duplicate found
  • Matches behavior of function definitions

Test Results

All project3 test cases pass:

  • err_01: ✓ (Undeclared use)
  • err_02: ✓ (Undeclared use)
  • err_04: ✓ (Definition of incomplete type for array)
  • ok_01: ✓ (Complex types)
  • ok_03: ✓ (Various scenarios)

Additional validation:

  • int main(int a, int a); → Correctly errors with "Redefinition of 'a'"
  • int main2(int a, char a[20]) {} → Correctly errors with "Redefinition of 'a'"
  • int func(int a, char b, int a); → Correctly errors with "Redefinition of 'a'"
  • int func1(int a, char b); → Passes correctly
Original prompt

项目要求Project 3 - Semantic Check Part 1 (Rev. v4)
2025 年 11 月 12 日
我们于 Oct 31 发布了 v2 版本的文档,修复了文档里面的一些错误,请以 Blackboard 上最新的文档
为准。
我们于 Nov 11 发布了 v3 版本的文档,修复了文档里面的一些错误并添加了一条新的项目假设,请以
Blackboard 上最新的文档为准。
我们于 Nov 12 发布了 v4 版本的文档,明确规定了 Definition of incomplete type 的处理情况、并
详细解释了一个常见问题,请以 Blackboard 上最新的文档为准。
1 项目要求
在 Project 2 中,你已经成功构建了 Splc 语言的解析器,能够将源代码转化为语法树,并检查出语法错误。
但是,语法正确并不意味着源代码在逻辑上(即语义上)是正确的。
在 Project 3 中,你将进入语义分析的第一步:实现类型系统 (Type System) 和符号表 (Symbol Table)。在
Project 4 中,你将基于前面的类型系统和符号表进行完整的语义检查。

  1. 实现类型系统:在 Java 中实现一套类型系统,并将 Parse Tree 中的变量声明(specifier 和 varDec)转
    化为描述该变量的类型的 Java 对象。
  2. 实现符号表:实现基于作用域 (Scope) 的符号表。
  3. 执行全面的语义检查:遍历 Parse Tree,结合符号表找出并报告所有发现的语义错误。在本次 Project 中,
    你只需要关注第三章中所描述的几种语义错误即可。
    1.1 对 Project 2 的修订
    在开始 Project 3 前,请在 Splc.g4 中为 globalDef 添加一条新的规则:
    函数声明:specifier Identifier LPAREN funcArgs RPAREN SEMI
    1.2 项目假设
    在后续所有 Project 中,所有测试样例均不会出现词法错误与语法错误,你可以删除 Project 2 中为错误恢
    复做出的特判。
    在 Project 3 & 4 中,我们做出如下假设:样例可能存在语义错误;(v3 新增) specifier 中的完整结构
    体规则出现时,它在语法树中一定是全局变量定义或全局结构体声明的任意次子节点,即它不会出现在函数参
    数(包含函数声明和函数定义)、函数体内。
    1
    1.3 扩展要求
    扩展部分在每个 Project 之间都是独立计分的,在后续的 Project 中移除对某扩展部分的支持不影响前
    序 Project 的分数。也就是说,你可以选择在前面的 Project 中完成较为简单的扩展任务;如果你发现
    在后续的 Project 中完成扩展部分过于困难,你可以选择不完成后续 Project 的扩展部分,这样不会影
    响你前面 Project 的分数。
    本项目的扩展部分是 Project 2 中的延续:你需要确保你的类型系统能够正确处理 结构体 和 指针 的相关
    语法。并且能够检查结构体中的 incomplete type 的情况。
    2
    1.4 名词解释
    • type specifier:(语法结构上的)类型说明符。对应 Project 2 文档章节 2.2 类型说明符。
    • declarator:(语法结构上的)声明符。在 Splc 语言中包含两种:变量声明 (varDec),会出现在全局变
    量定义、局部变量定义、完整结构体中的成员声明;以及函数声明 (上述修订新增)。
    1.5 解释:declaration & definition
    正式定义:
    • [1.5.1] A declaration specifies the interpretation and attributes of a set of identifiers.
    • [1.5.2] A definition of an identifier is a declaration for that identifier that:
    − for an object (variable), causes storage to be reserved for that object (variable);
    − for a function, includes the function body.
    声明 (Declaration) 就像在电话簿的索引(符号表)里说:“我们要登记一个人,名字叫 x,他是一个 int 类型。”
    编译器看到声明后,会说:“好的,我认识 x 了。如果我看到有人使用 x,我知道它应该被当作一个 int 来对
    待。”
    声明不分配内存(对于变量)或不提供函数体(对于函数)。
    尽管 C 语言中可以对同一个对象(变量或函数)进行多次声明,但是在我们的 Splc 中,不存在像 C 语言
    中那样的变量声明(extern int a;),仅存在函数声明。并且我们规定:同名的函数声明只能出现一次,并且
    其定义(若有)一定与其声明相符1。
    定义 (Definition) 就像在电话簿的具体条目里说:“x 的具体住址是内存 0x1000(请在这里给他分配空间)。”或
    者“myFunc 的具体工作内容是 { ... }(请把这段代码编译成机器码)。”
    定义会分配存储空间(对于变量)或提供函数体(对于函数)。
    在整个程序中,同一个实体(变量或函数)2只能被定义一次。
    一个定义同时也是一个声明。它在“创建”这个实体的同时,也“介绍”了它自己。
    注意,我们只对变量和函数说 Definition,我们从不对一个完整结构体的声明说它是一个定义。
    示例
    int a() {} // 这是函数 a' 的定义,也是一个声明 int b(char); // 这是函数 b' 的声明
    int b(char); // 这是函数 `b' 的重复声明,Splc 不允许这种情况
    int global_var; // 这是全局变量的定义
    int main() {
    global_var = 3;
    int local_var; // 这是局部变量的定义
    }
    1判断定义与声明是否相同是下一次 Project 的任务。
    2显然,同一个 Identifier 可能指向不同的实体。
    3
    2 Project 3 要求
    2.1 类型系统
    你的类型系统需要能够解析语法树中的 specifier 与 varDec,并表达以下类型:
    • 基础类型(Primitive Type):包含 int 与 char。
    • 定长数组类型(Array Type):包含基础类型 (element type) 和数组长度,如 int a[10] 和 char b[2][3]。
    • 结构体类型(Structure Type):包括完整声明的结构体(内含字段声明)与不完整声明的结构体两种。
    • 指针类型(Pointer Type):包含被指向的类型,例如 int *a。
    • 你支持的所有类型的任意组合,例如 struct a[10]、int *a[123] 和 int (*a)[123]。
    完整定义:
    • [2.1.1] The meaning of a value stored in an object or returned by a function is determined by the type of
    the expression used to access it. (An identifier declared to be an object is the simplest such expression;
    the type is specified in the declaration of the identifier.)
    • [2.1.2] Types are partitioned into object types (types that describe objects) and function types (types
    that describe functions). At various points within a translation unit an object type may be incomplete
    (lacking sufficient information to determine the size of objects of that type) or complete (having sufficient
    information).
    • [2.1.3] The char and int are called the basic types. The basic types are complete object types.
    • [2.1.4] A function type describes a function with specified return type. A function type is characterized
    by its return type and the number and types of its parameters.
    • [2.1.5] Any number of derived types can be constructed from the object types3
    , as follows:
    − [2.1.6] An array type describes a contiguously allocated nonempty set of objects with a particular
    member object type, called the element type. The element type shall be complete whenever the array
    type is specified. Array types are characterized by their element type and by the number of elements
    in the array. An array type is said to be derived from its element type, and if its element type is T,
    the array type is sometimes called “array of T”. The construction of an array type from an element
    type is called “array type derivation”.
    − [2.1.7] A structure type describes a sequentially allocated nonempty set of member objects (and, in
    certain circumstances, an incomplete array)(v3 删除), each of which has an optionally specified name
    and possibly distinct type.
    − [2.1.8] A pointer type may be derived from an object type, called the referenced type. A pointer type
    describes an object whose value provides a reference to an entity of the referenced type. A pointer
    type derived from the referenced type T is sometimes c...

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI self-assigned this Nov 13, 2025
Copilot AI and others added 2 commits November 13, 2025 02:59
Co-authored-by: wuzhi456 <217564920+wuzhi456@users.noreply.github.com>
…tely

Co-authored-by: wuzhi456 <217564920+wuzhi456@users.noreply.github.com>
Copilot AI changed the title [WIP] Implement type system and symbol table for semantic analysis Fix incomplete type checking for arrays with struct element types Nov 13, 2025
Copilot AI requested a review from wuzhi456 November 13, 2025 03:07
@wuzhi456

Copy link
Copy Markdown
Owner

@copilot int main(int a, int a); // Error: Redefinition of 'a' 奇怪的是现在这个识别不出来错,但是int main2(int a, char a[20]) { // Error: Redefinition of 'a'
}这个能识别的了

Co-authored-by: wuzhi456 <217564920+wuzhi456@users.noreply.github.com>

Copilot AI commented Nov 13, 2025

Copy link
Copy Markdown
Author

@copilot int main(int a, int a); // Error: Redefinition of 'a' 奇怪的是现在这个识别不出来错,但是int main2(int a, char a[20]) { // Error: Redefinition of 'a'
}这个能识别的了

Fixed in commit 2f552c1. Function declarations now check for duplicate parameter names, matching the behavior of function definitions. Both int main(int a, int a); and int main2(int a, char a[20]) {} now correctly error with "Redefinition of 'a'".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants